/**
 ****************************************************************************************************
 * @file        audioplay.c
 * @author      正点原子团队(ALIENTEK)
 * @version     V1.0
 * @date        2022-09-06
 * @brief       音乐播放器 应用代码
 * @license     Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
 ****************************************************************************************************
 * @attention
 *
 * 实验平台:正点原子 阿波罗 H743开发板
 * 在线视频:www.yuanzige.com
 * 技术论坛:www.openedv.com
 * 公司网址:www.alientek.com
 * 购买地址:openedv.taobao.com
 *
 * 修改说明
 * V1.0 20220906
 * 第一次发布
 *
 ****************************************************************************************************
 */

#include "audioplay.h"
#include "malloc.h"
#include "es8388.h"
#include "mysai.h"
#include "lcd.h"
#include "key_led.h"

#include "ff.h"
#include "ffconf.h"
#include "exfuns.h"
#include "file_opera.h"
#include "arm_math.h"
#include "arm_const_structs.h"
#include "lcd.h"
#include <string.h>

#include "FreeRTOS.h"
#include "semphr.h"
#include "queue.h"
#include "cmsis_os.h"

__audiodev g_audiodev; /* 音乐播放控制器 */
extern osThreadId_t Task_ANSHandle;
extern osThreadId_t Task_RecorderHandle;

/**
 * @brief       开始音频播放
 * @param       无
 * @retval      无
 */
void audio_start(void)
{
    g_audiodev.status = 3 << 0; /* 开始播放+非暂停 */
    sai1_play_start();
}

/**
 * @brief       停止音频播放
 * @param       无
 * @retval      无
 */
void audio_stop(void)
{
    g_audiodev.status = 0;
    sai1_play_stop();
}

/**
 * @brief       得到path路径下，目标文件的总数
 * @param       path : 文件路径
 * @retval      有效文件总数
 */
uint16_t audio_get_tnum(uint8_t *path)
{
    uint8_t res;
    uint16_t rval = 0;
    DIR tdir;           /* 临时目录 */
    FILINFO *tfileinfo; /* 临时文件信息 */

    tfileinfo = (FILINFO *)mymalloc(SRAMIN, sizeof(FILINFO)); /* 申请内存 */

    res = f_opendir(&tdir, (const TCHAR *)path); /* 打开目录 */
    if ((res == FR_OK) && tfileinfo)
    {
        while (1) /* 查询总的有效文件数 */
        {
            res = f_readdir(&tdir, tfileinfo); /* 读取目录下的一个文件 */
            if ((res != FR_OK) || (tfileinfo->fname[0] == 0))
            {
                break; /* 错误了/到末尾了,退出 */
            }

            res = exfuns_file_type(tfileinfo->fname);
            if ((res & 0xF0) == 0x40) /* 取高四位,看看是不是音乐文件 */
            {
                rval++; /* 有效文件数增加1 */
            }
        }
    }

    myfree(SRAMIN, tfileinfo); /* 释放内存 */

    return rval;
}

/**
 * @brief       显示曲目索引
 * @param       index : 当前索引
 * @param       total : 总文件数
 * @retval      无
 */
void audio_index_show(uint16_t index, uint16_t total)
{
    /* 显示当前曲目的索引,及总曲目数 */
    lcd_show_num(30 + 0, 40 + 40, index, 3, 16, RED); /* 索引 */
    lcd_show_char(30 + 24, 40 + 40, '/', 16, 0, RED);
    lcd_show_num(30 + 32, 40 + 40, total, 3, 16, RED); /* 总曲目 */
}

/**
 * @brief       显示播放时间,比特率 信息
 * @param       totsec : 音频文件总时间长度
 * @param       cursec : 当前播放时间
 * @param       bitrate: 比特率(位速)
 * @retval      无
 */
void audio_msg_show(uint32_t totsec, uint32_t cursec, uint32_t bitrate)
{
    static uint16_t playtime = 0xFFFF; /* 放时间标记 */

    if (playtime != cursec) /* 需要更新显示时间 */
    {
        playtime = cursec;

        /* 显示播放时间 */
        lcd_show_num(30, 40 + 20, playtime / 60, 2, 16, RED); /* 分钟 */
        lcd_show_char(30 + 16, 40 + 20, ':', 16, 0, RED);
        lcd_show_num(30 + 24, 40 + 20, playtime % 60, 2, 16, RED); /* 秒钟 */
        lcd_show_char(30 + 40, 40 + 20, '/', 16, 0, RED);

        /* 显示总时间 */
        lcd_show_num(30 + 48, 40 + 20, totsec / 60, 2, 16, RED); /* 分钟 */
        lcd_show_char(30 + 64, 40 + 20, ':', 16, 0, RED);
        lcd_show_num(30 + 72, 40 + 20, totsec % 60, 2, 16, RED); /* 秒钟 */

        /* 显示位率 */
        lcd_show_num(30 + 110, 40 + 20, bitrate / 1000, 4, 16, RED); /* 显示位率 */
        lcd_show_string(30 + 110 + 32, 40 + 20, 200, 16, 16, "Kbps", RED);
    }
}

/**
 * @brief       播放音乐
 * @param       无
 * @retval      无
 */
void audio_play(void)
{
    uint8_t res;
    DIR wavdir;           /* 目录 */
    FILINFO *wavfileinfo; /* 文件信息 */
    uint8_t *pname;       /* 带路径的文件名 */
    uint16_t totwavnum;   /* 音乐文件总数 */
    uint16_t curindex;    /* 当前索引 */
    uint8_t key;          /* 键值 */
    uint32_t temp;
    uint32_t *wavoffsettbl; /* 音乐offset索引表 */

    es8388_adda_cfg(1, 0);   /* 开启DAC关闭ADC */
    es8388_output_cfg(1, 1); /* DAC选择通道1输出 */

    while (f_opendir(&wavdir, "0:/Music")) /* 打开音乐文件夹 */
    {
        lcd_show_string(30, 190, 240, 16, 16, "Music file error!", BLUE);
        osDelay(200);
        lcd_fill(30, 190, 240, 206, WHITE); /* 清除显示 */
        osDelay(200);
    }

    totwavnum = audio_get_tnum((uint8_t *)"0:/Music"); /* 得到总有效文件数 */
    while (totwavnum == 0)                             /* 音乐文件总数为0 */
    {
        lcd_show_string(30, 190, 240, 16, 16, "Without music file!", BLUE);
        osDelay(200);
        lcd_fill(30, 190, 240, 146, WHITE); /* 清除显示 */
        osDelay(200);
    }
    wavfileinfo = (FILINFO *)mymalloc(SRAMIN, sizeof(FILINFO)); /* 申请内存 */
    pname = mymalloc(SRAMIN, _MAX_LFN * 2 + 1);                 /* 为带路径的文件名分配内存 */
    wavoffsettbl = mymalloc(SRAMIN, 4 * totwavnum);             /* 申请4*totwavnum个字节的内存,用于存放音乐文件off block索引 */
    while (!wavfileinfo || !pname || !wavoffsettbl)             /* 内存分配出错 */
    {
        lcd_show_string(30, 190, 240, 16, 16, "malloc error!", BLUE);
        osDelay(200);
        lcd_fill(30, 190, 240, 146, WHITE); /* 清除显示 */
        osDelay(200);
    }

    /* 记录索引 */
    res = f_opendir(&wavdir, "0:/Music"); /* 打开目录 */
    if (res == FR_OK)
    {
        curindex = 0; /* 当前索引为0 */
        while (1)     /* 全部查询一遍 */
        {
            temp = wavdir.dptr;                    /* 记录当前index */
            res = f_readdir(&wavdir, wavfileinfo); /* 读取目录下的一个文件 */
            if ((res != FR_OK) || (wavfileinfo->fname[0] == 0))
            {
                break;
            } /* 错误了/到末尾了,退出 */
            res = exfuns_file_type(wavfileinfo->fname);
            if ((res & 0xF0) == 0x40) /* 取高四位,看看是不是音乐文件 */
            {
                wavoffsettbl[curindex] = temp; /* 记录索引 */
                curindex++;
            }
        }
    }

    curindex = 0;                                        /* 从0开始显示 */
    res = f_opendir(&wavdir, (const TCHAR *)"0:/Music"); /* 打开目录 */
    while (res == FR_OK)                                 /* 打开成功 */
    {
        dir_sdi(&wavdir, wavoffsettbl[curindex]); /* 改变当前目录索引 */
        res = f_readdir(&wavdir, wavfileinfo);    /* 读取目录下的一个文件 */
        if ((res != FR_OK) || (wavfileinfo->fname[0] == 0))
        {
            break;
        } /* 错误了/到末尾了,退出 */

        strcpy((char *)pname, "0:/Music/");                                                   /* 复制路径(目录) */
        strcat((char *)pname, (const char *)wavfileinfo->fname);                              /* 将文件名接在后面 */
        lcd_fill(30, 40, lcddev.width - 1, 40 + 16 * 5, WHITE);                               /* 清除之前的显示 */
        lcd_show_string(30, 40, lcddev.width - 60, 16, 16, (char *)wavfileinfo->fname, BLUE); /* 显示歌曲名字 */
        audio_index_show(curindex + 1, totwavnum);

        key = audio_play_song(pname); /* 播放这个音频文件 */
        if (key == key_left)          /* 上一曲 */
        {
            if (curindex)
            {
                curindex--;
            }
            else
            {
                curindex = totwavnum - 1;
            }
        }
        else if (key == key_right) /* 下一曲 */
        {
            curindex++;
            if (curindex >= totwavnum)
            {
                curindex = 0;
            } /* 到末尾的时候,自动从头开始 */
        }
        else
        {
            break;
        } /* 产生了错误 */
    }

    myfree(SRAMIN, wavfileinfo);  /* 释放内存 */
    myfree(SRAMIN, pname);        /* 释放内存 */
    myfree(SRAMIN, wavoffsettbl); /* 释放内存 */
}
/**
 * @brief       播放某个音频文件
 * @param       fname : 文件名
 * @retval      按键值
 *   @arg       KEY0_PRES , 下一曲.
 *   @arg       KEY2_PRES , 上一曲.
 *   @arg       其他 , 错误
 */
uint8_t audio_play_song(uint8_t *fname)
{
    uint8_t res;

    res = exfuns_file_type((char *)fname);
    switch (res)
    {
    case T_WAV:
        res = wav_play_song(fname);
        break;

    default: /* 其他文件,自动跳转到下一曲 */
        printf("can't play:%s\r\n", fname);
        res = key_right;
        break;
    }
    return res;
}

void AppTask_AudioPlay(void *argument)
{
    /* USER CODE BEGIN AppTask_Audio_Play */
    lcd_init();
    exfuns_init();
    FRESULT res = f_mount(&SDFatFS, "0:", 1);
    if (res == FR_OK)
    {   lcd_show_string(30, 40 + 1 * 30, 240, 24, 24, "FatFS mount ok", BLACK); }
    else
    {
        lcd_show_string(30, 40 + 1 * 30, 240, 24, 24, "No file system!", RED);
        BYTE workBuffer[4 * BLOCKSIZE];
        DWORD cluster_size = 0;
        FRESULT res = f_mkfs("0:", FM_FAT32, cluster_size, workBuffer, 4 * BLOCKSIZE);
        if (res == FR_OK)
        {   lcd_show_string(30, 40 + 2 * 30, 240, 24, 24, "Format OK!", RED);   }
        else
        {   lcd_show_string(30, 40 + 2 * 30, 240, 24, 24, "Format Fail!", RED); }
    }
    if (key_scan(0) == key_down)    /* 若要切换到其他例程前，需在开机前按住key_down以卸载磁盘 */
    {   f_mount(0, "0:", 0);    }

    es8388_init();
    es8388_adda_cfg(1, 1);
    es8388_output_cfg(1, 1);
    es8388_hpvol_set(10);
    es8388_spkvol_set(10);
    xTaskNotifyGive(Task_RecorderHandle);
    /* Infinite loop */
    for (;;)
    {
        // audio_play();
        osDelay(10);
    }
    /* USER CODE END AppTask_Audio_Play */
}

extern ADC_HandleTypeDef hadc1;
void AppTask_RV1ADC_Vol(void *argument)
{
    /* USER CODE BEGIN AppTask_RV1ADC_Vol */
    uint32_t adc_value;
    uint8_t current_volume = 10;
    uint8_t front_volume = 10;
    /* Infinite loop */
    for (;;)
    {
        HAL_ADC_Start(&hadc1);
        HAL_ADC_PollForConversion(&hadc1, 1);
        adc_value = HAL_ADC_GetValue(&hadc1);
        HAL_ADC_Stop(&hadc1);

        current_volume = adc_value/2000;
        if(current_volume != front_volume)
        {
            es8388_hpvol_set(current_volume);
            es8388_spkvol_set(current_volume);
            front_volume = current_volume;
        }

        osDelay(pdMS_TO_TICKS(500));
    }
    /* USER CODE END AppTask_RV1ADC_Vol */
}
float32_t IIRCoeffs32LP[NUM_STAGES*5] = {
    1.0f,-1.999997f,1.0f,1.999050f,-0.999052f,
    1.0f,-1.999997f,1.0f,1.997055f,-0.997066f
};
